<?php


namespace Um\WechatPay;

use Ke\Helper\DateHelper;
use Um\WechatPay\V3Api\V3ApiCore;
use Um\WechatPay\V3Api\VoucherApi;

class PayV3Api
{

	private static $instances = [];

	public static function getInstance(string $name)
	{
		if (!isset(self::$instances[$name])) {
			self::$instances[$name] = new static();
		}
		return self::$instances[$name];
	}

	private $isInit = false;

	protected $merchantId = '';

	protected $serialNo = '';

	protected $privateKeyFile = '';

	protected $privateKey = '';

	protected $v2key = '';

	protected $subApiMaps = [
		'voucher' => VoucherApi::class,
	];

	protected $subApiInstances = [

	];

	/**
	 * @param string $merchantId
	 * @param string $serialNo
	 * @param string $appId
	 * @param string $privateKeyFile
	 * @return $this
	 * @throws PayException
	 */
	public function init(string $merchantId, string $serialNo, string $privateKeyFile = null)
	{
		if ($this->isInit) return $this;
		if (empty($merchantId))
			throw new PayException('PayV3Api::init 必须指定商户号');
		if (empty($serialNo))
			throw new PayException('PayV3Api::init 必须指定 SerialNo');
		$this->merchantId = $merchantId;
		$this->serialNo = $serialNo;
		if (isset($privateKeyFile))
			$this->setPrivateKeyFile($privateKeyFile);
		$this->isInit;
		return $this;
	}

	public function setV2Key(string $v2key)
	{
		if (empty($v2key))
			throw new PayException('商户 v2key 不得为空');
		$this->v2key = $v2key;
		return $this;
	}

	public function newV2Signer()
	{
		if (empty($this->v2key))
			throw new PayException('未指定商户 v2key');
		$payV2 = new PayV2Signer($this->v2key);
		return $payV2;
	}

	public function getMpSendCouponSign(array $cards, string $type = 'sha256')
	{
		$results = [];
		foreach ($cards as $index => $cardItem) {
			$num = 0;
			foreach ($cardItem as $key => $item) {
				$results[$key . $num] = $item;
			}
			$num++;
		}
		$results['send_coupon_merchant'] = $this->merchantId;

		return $this->newV2Signer($this->v2key)->setSignData($results)->exportSign($type);
	}

	/**
	 * @return bool
	 */
	public function isInit(): bool
	{
		return $this->isInit;
	}

	/**
	 * @return string
	 */
	public function getMerchantId(): string
	{
		return $this->merchantId;
	}

	/**
	 * @return string
	 */
	public function getSerialNo(): string
	{
		return $this->serialNo;
	}

	/**
	 * @return string
	 */
	public function getPrivateKeyFile()
	{
		return $this->privateKeyFile;
	}

	public function setPrivateKeyFile(string $file)
	{
		if (empty($file) || !is_file($file))
			throw new \Exception('无效的 PrivateKey 文件！');
		if ($this->privateKeyFile !== $file) {
			$this->privateKeyFile = $file;
			$this->privateKey = file_get_contents($file);
		}
		return $this;
	}

	public function setPrivateKey(string $content)
	{
		$this->privateKey = $content;
		return $this;
	}

	public function newRequest($url)
	{
		$req = new PayV3Request($url);
		if (empty($this->privateKey))
			throw new PayException('未设定有效的 PrivateKey！');
		$req->setPrivateKey($this->privateKey);
		$req->setSerialNo($this->serialNo);
		$req->setMerchantId($this->merchantId);
		return $req;
	}

	public function formatDateTime($date)
	{
		if (is_string($date) || is_numeric($date))
			$date = DateHelper::withTime($date);
		if (!isset($date))
			$date = time();
		return $date->format('c');
	}

	/**
	 * @param string $name
	 * @return V3ApiCore|VoucherApi
	 * @throws PayException
	 */
	public function getSubApi(string $name)
	{
		if (!isset($this->subApiMaps[$name]))
			throw new PayException('未知的接口对象');
		$class = $this->subApiMaps[$name];
		if (!isset($this->subApiInstances[$name]))
			$this->subApiInstances[$name] = new $class($this);
		return $this->subApiInstances[$name];
	}

	/**
	 * @return VoucherApi
	 * @throws PayException
	 */
	public function getVoucherApi()
	{
		return $this->getSubApi('voucher');
	}

	/**
	 * @param PayV3Request $request
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function filterResponse(PayV3Request $request)
	{
		if (!$request->isSend())
			throw new PayException('未发送的请求');
		return new PayV3Status($request->getResponseAsJson());
	}
}